<?php
    header("Content-type: text/html; charset=utf-8");

/************************ 密码方面的自定义方法 Start ************************/
    /**
     * authcode加密解密函数，【Discuz!经典代码。异或方式的加密、解密方式】
     *
     * @param   string  $string     需要 加密 或 解密 的字符串
     * @param   string  $operation  DECODE表示解密,其它表示加密
     * @param   string  $key        密匙
     * @param   int     $expiry     密文有效期
     * @return  string  字符串类型的返回结果
     */
    function authcode($string, $operation = 'DECODE', $key = 'discuz_auth_key', $expiry = 0)
    {
        // 动态密匙长度，相同的明文会生成不同密文就是依靠动态密匙
        // 加入随机密钥，可以令密文无任何规律，即便是原文和密钥完全相同，加密结果也会每次不同，增大破解难度。
        // 取值越大，密文变动规律越大，密文变化 = 16 的 $ckey_length 次方
        // 当此值为 0 时，则不产生随机密钥
        $ckey_length = 4;

        // 密匙
        $key = md5($key);

        // 密匙a会参与加解密
        $keya = md5(substr($key, 0, 16));
        // 密匙b会用来做数据完整性验证
        $keyb = md5(substr($key, 16, 16));
        // 密匙c用于变化生成的密文
        $keyc = $ckey_length ? ($operation == 'DECODE' ? substr($string, 0, $ckey_length) : substr(md5(microtime()), -$ckey_length)) : '';
        // 参与运算的密匙
        $cryptkey = $keya.md5($keya.$keyc);
        $key_length = strlen($cryptkey);
        // 明文，前10位用来保存时间戳，解密时验证数据有效性，10到26位用来保存$keyb(密匙b)，
        //解密时会通过这个密匙验证数据完整性
        // 如果是解码的话，会从第$ckey_length位开始，因为密文前$ckey_length位保存 动态密匙，以保证解密正确
        $string = $operation == 'DECODE' ? base64_decode(substr($string, $ckey_length)) :
                    sprintf('%010d', $expiry ? $expiry + time() : 0).substr(md5($string.$keyb), 0, 16).$string;
        $string_length = strlen($string);
        $result = '';
        $box = range(0, 255);
        $rndkey = array();
        // 产生密匙簿
        for ($i = 0; $i <= 255; $i++) {
            $rndkey[$i] = ord($cryptkey[$i % $key_length]);
        }
        // 用固定的算法，打乱密匙簿，增加随机性，好像很复杂，实际上对并不会增加密文的强度
        for ($j = $i = 0; $i < 256; $i++) {
            $j = ($j + $box[$i] + $rndkey[$i]) % 256;
            $tmp = $box[$i];
            $box[$i] = $box[$j];
            $box[$j] = $tmp;
        }
        // 核心加解密部分
        for ($a = $j = $i = 0; $i < $string_length; $i++) {
            $a = ($a + 1) % 256;
            $j = ($j + $box[$a]) % 256;
            $tmp = $box[$a];
            $box[$a] = $box[$j];
            $box[$j] = $tmp;
            // 从密匙簿得出密匙进行异或，再转成字符
            $result .= chr(ord($string[$i]) ^ ($box[($box[$a] + $box[$j]) % 256]));
        }
        if ($operation == 'DECODE') {
            // substr($result, 0, 10) == 0 验证数据有效性
            // substr($result, 0, 10) - time() > 0 验证数据有效性
            // substr($result, 10, 16) == substr(md5(substr($result, 26).$keyb), 0, 16) 验证数据完整性
            // 验证数据有效性，请看未加密明文的格式
            if((substr($result, 0, 10) == 0 || substr($result, 0, 10) - time() > 0) && substr($result, 10, 16) == substr(md5(substr($result, 26).$keyb), 0, 16)) {
                return substr($result, 26);
            } else {
                return '';
            }
        } else {
            // 把动态密匙保存在密文里，这也是为什么同样的明文，生产不同密文后能解密的原因
            // 因为加密后的密文可能是一些特殊字符，复制过程可能会丢失，所以用base64编码
            return $keyc.str_replace('=', '', base64_encode($result));
        }
    }

    /**
     * 加密函数
     *
     * @param   string  $str 需要加密的字符串
     * @param   string  $key 密钥
     * @return  string  返回加密结果
     */
    function encrypt($str, $key = '')
    {
        if (empty($str)) {
            return $str;
        }
        if (empty($key)) {
            $key = md5('MD5_KEY');
        }
        $chars = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-_.";
        $ikey  = "-x6g6ZWm2G9g_vr0Bo.pOq3kRIxsZ6rm";
        $nh1   = rand(0, 64);
        $nh2   = rand(0, 64);
        $nh3   = rand(0, 64);
        $ch1   = $chars{$nh1};
        $ch2   = $chars{$nh2};
        $ch3   = $chars{$nh3};
        $nhnum = $nh1 + $nh2 + $nh3;
        $knum  = 0;
        $i     = 0;
        while (isset($key{$i})) {
            $knum += ord($key{$i++});
        }
        $mdKey = substr(md5(md5(md5($key . $ch1) . $ch2 . $ikey) . $ch3), $nhnum % 8, $knum % 8 + 16);
        $str   = base64_encode(time() . '_' . $str);
        $str   = str_replace(['+', '/', '='], ['-', '_', '.'], $str);
        $tmp   = '';
        $j     = 0;
        $k     = 0;
        $tlen  = strlen($str);
        $klen  = strlen($mdKey);
        for ($i = 0; $i < $tlen; $i++) {
            $k = $k == $klen ? 0 : $k;
            $j = ($nhnum + strpos($chars, $str{$i}) + ord($mdKey{$k++})) % 64;
            $tmp .= $chars{$j};
        }
        $tmplen = strlen($tmp);
        $tmp    = substr_replace($tmp, $ch3, $nh2 % ++$tmplen,  0);
        $tmp    = substr_replace($tmp, $ch2, $nh1 % ++$tmplen,  0);
        $tmp    = substr_replace($tmp, $ch1, $knum % ++$tmplen, 0);

        return $tmp;
    }

    /**
     * 解密函数
     *
     * @param   string  $str 需要解密的字符串
     * @param   string  $key 密匙
     * @return  string  字符串类型的返回结果
     */
    function decrypt($str, $key = '', $ttl = 0)
    {
        if (empty($str)) {
            return $str;
        }
        if (empty($key)) {
            $key = md5('MD5_KEY');
        }

        $chars = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-_.";
        $ikey  = "-x6g6ZWm2G9g_vr0Bo.pOq3kRIxsZ6rm";
        $knum  = 0;
        $i     = 0;
        $tlen  = @strlen($str);
        while (isset($key{$i})) {
            $knum += ord($key{$i++});
        }
        $ch1   = @$str{$knum % $tlen};
        $nh1   = strpos($chars, $ch1);
        $str   = @substr_replace($str, '', $knum % $tlen--, 1);
        $ch2   = @$str{$nh1 % $tlen};
        $nh2   = @strpos($chars, $ch2);
        $str   = @substr_replace($str, '', $nh1 % $tlen--, 1);
        $ch3   = @$str{$nh2 % $tlen};
        $nh3   = @strpos($chars, $ch3);
        $str   = @substr_replace($str, '', $nh2 % $tlen--, 1);
        $nhnum = $nh1 + $nh2 + $nh3;
        $mdKey = substr(md5(md5(md5($key . $ch1) . $ch2 . $ikey) . $ch3), $nhnum % 8, $knum % 8 + 16);
        $tmp   = '';
        $j     = 0;
        $k     = 0;
        $tlen  = @strlen($str);
        $klen  = @strlen($mdKey);
        for ($i = 0; $i < $tlen; $i++) {
            $k = $k == $klen ? 0 : $k;
            $j = strpos($chars, $str{$i}) - $nhnum - ord($mdKey{$k++});
            while ($j < 0) {
                $j += 64;
            }
            $tmp .= $chars{$j};
        }
        $tmp = str_replace(['-', '_', '.'], ['+', '/', '='], $tmp);
        $tmp = trim(base64_decode($tmp));

        if (preg_match("/\d{10}_/s", substr($tmp, 0, 11))) {
            if ($ttl > 0 && (time() - substr($tmp, 0, 11) > $ttl)) {
                $tmp = null;
            } else {
                $tmp = substr($tmp, 11);
            }
        }

        return $tmp;
    }

    /**
     * 加密函数【使用位运算的二进制加密方式，（缺点：每次生成的值是固定，极易被暴力破解）】
     *
     * @param   string  $str    需要加密的字符串
     * @param   string  $key    密钥
     * @return  string  加密后的字符串
     */
    function encryptLow1($str, $key = 'AUTH_KEY')
    {
        $coded = '';
        $keylength = strlen($key);

        for ($i = 0, $count = strlen($str); $i < $count; $i = $i+$keylength)
        {
            $coded .= substr($str, $i, $keylength) ^ $key;
        }

        return str_replace('=', '', base64_encode($coded));
    }

    /**
     * 解密函数【使用位运算的二进制解密方式】
     *
     * @param   string  $str    加密后的字符串
     * @param   string  $key    密钥
     * @return  string  加密前的字符串
     */
    function decryptLow1($str, $key = 'AUTH_KEY')
    {
        $coded = '';
        $keylength = strlen($key);
        $str = base64_decode($str);

        for ($i = 0, $count = strlen($str); $i < $count; $i += $keylength)
        {
            $coded .= substr($str, $i, $keylength) ^ $key;
        }

        return $coded;
    }
/************************ 密码方面的自定义方法 Start ************************/

/************************ 数字方面的自定义方法 Start ************************/
    /**
     * 阿拉伯数字转中文【缺点：最大值不能超过14位整数】
     *
     * @param   int     $num     需要转化的整数
     * @param   string  $mode    是否转成符合汉语语法的文字
     * @return  string  $retval  中文字符串
     */
    function chNum($num, $mode=true)
    {
        $char   = array("零","一","二","三","四","五","六","七","八","九");
//        $char   = array("零","壹","贰","叁","肆","伍","陆","柒","捌","玖");
        $dw     = array("","十","百","千","","万","亿","兆");
//        $dw     = array("","拾","佰","仟","","万","亿","兆");
        $dec    = "点";
        $retval = "";
        if ($mode) {
            preg_match_all("/^0*(\d*)\.?(\d*)/", $num, $ar);
        } else {
            preg_match_all("/(\d*)\.?(\d*)/", $num, $ar);
        }
        if ($ar[2][0] != "") {
            $retval = $dec . chNum($ar[2][0],false); //如果有小数，先递归处理小数
        }
        if ($ar[1][0] != "") {
            $str = strrev($ar[1][0]);
            for($i = 0; $i < strlen($str); $i++) {
                $out[$i] = $char[$str[$i]];
                if ($mode) {
                    $out[$i] .= $str[$i] != "0"? $dw[$i%4] : "";
                    if (isset($str[$i]) && isset($str[$i-1])) {
                        if ($str[$i] + $str[$i-1] == 0) {
                            $out[$i] = "";
                        }
                    }
                    if ($i%4 == 0) {
                        $out[$i] .= $dw[4 + floor($i/4)];
                    }
                }
            }
            $retval = join("",array_reverse($out)) . $retval;
        }
        return $retval;
    }
/************************ 数字方面的自定义方法  End  ************************/

/************************ 时间方面的自定义方法 Start ************************/
    /**
     * 获取指定时区的时间
     *
     * @param   string  $dateFormat
     * @param   string  $time(指定的时间戳)
     * @param   int     $timezone(例：-1为东一区，+1为西1区)
     * @return  string  日期格式的时间
     */
    function worldDate($dateFormat = "Y-m-d", $time = null, $timezone = 0)
    {
        if (!isset($time)) {
            $time = time();
        }
        $oldTimezone = date_default_timezone_get();

        //设置默认时区为指定时区
        if (is_numeric($timezone)) {
            if (($timezone < -14) || (12 < $timezone)) {
                $timezone = 0;
            }
            if ($timezone > 0) {
                $timezone = "Etc/GMT+" . $timezone;
            } else {
                $timezone = "Etc/GMT" . $timezone;
            }
        }

        date_default_timezone_set($timezone);
        $newDate = date($dateFormat, $time);
        date_default_timezone_set($oldTimezone);    //将默认时区调回为原来的时区

        return $newDate;
    }

    /**
     * ISO8601格式时间
     *
     * @param   number  $time        指定的时间戳
     * @return  string  $expiration  国际标准ISO 8601的时间格式
     */
    function gmtISO8601($time) {
        $dtStr      = date("c", $time);
        $mydatetime = new \DateTime($dtStr);
        $expiration = $mydatetime->format(\DateTime::ISO8601);
        $pos        = strpos($expiration, '+');
        $expiration = substr($expiration, 0, $pos);

        return $expiration.".Z";
    }

/************************ 时间方面的自定义方法 Start ************************/

/************************ 通用项的自定义方法 Start ************************/
    /**
     * 截取字符串
     *
     * @param   string  $str      要截取的字符串
     * @param   int     $start    开始位置，默认从0开始
     * @param   int     $length   截取长度
     * @param   string  $charset  字符编码，默认UTF－8
     * @param   bool    $suffix   是否在截取后的字符后面显示省略号，默认true显示
     * @return  string
     */
    function msubstr($str, $start = 0, $length, $charset = "utf-8", $suffix = true)
    {
        if (function_exists("mb_substr")) {
            $len = mb_strlen($str, $charset);
            if ($suffix) {
                if ($len > $length) {
                    return mb_substr($str, $start, $length, $charset) . "...";
                } else {
                    return mb_substr($str, $start, $length, $charset);
                }
            } else {
                return mb_substr($str, $start, $length, $charset);
            }
        } elseif (function_exists('iconv_substr')) {
            $len = iconv_strlen($str);
            if ($suffix) {
                if ($len > $length) {
                    return iconv_substr($str, $start, $length, $charset) . "...";
                } else {
                    return iconv_substr($str, $start, $length, $charset);
                }
            } else {
                return iconv_substr($str, $start, $length, $charset);
            }
        }
        $re['utf-8']  = "/[x01-x7f]|[xc2-xdf][x80-xbf]|[xe0-xef][x80-xbf]{2}|[xf0-xff][x80-xbf]{3}/";
        $re['gb2312'] = "/[x01-x7f]|[xb0-xf7][xa0-xfe]/";
        $re['gbk']    = "/[x01-x7f]|[x81-xfe][x40-xfe]/";
        $re['big5']   = "/[x01-x7f]|[x81-xfe]([x40-x7e]|xa1-xfe])/";
        preg_match_all($re[$charset], $str, $match);
        $slice        = join("", array_slice($match[0], $start, $length));
        if ($suffix)
            return $slice . "…";
        return $slice;
    }

    /**
     * 格式化输出
     *
     * @param   mixed  $var    需要格式化输出的变量
     */
    function echo_r($var)
    {
        $iscli = php_sapi_name() == 'cli';
        if (!$iscli) echo '<pre>';
        print_r($var);
        if (!$iscli) echo '</pre>';
    }

/************************ 通用项的自定义方法  End  ************************/


?>